//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p.gui;

import java.awt.*;
import javax.swing.*;
import java.beans.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.event.*;
import javax.swing.table.*;

import ants.p2p.*;
import ants.p2p.query.*;
import ants.p2p.query.security.*;
import ants.p2p.utils.indexer.*;

import org.apache.log4j.*;

import com.borland.jbcl.layout.*;
import javax.swing.border.*;

public class QueryAntPanel extends JPanel implements PropertyChangeListener{
  public static String pic = "backgrounds/bg3.jpg";
  static Logger _logger = Logger.getLogger(QueryAntPanel.class.getName());

  Image buffer;
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextField jTextField1 = new JTextField();
  JLabel jLabel1 = new JLabel();
  JButton jButton1 = new JButton();
  JButton jButton2 = new JButton();
  QueryResultTable resultsTable;
  QueryMessage[] currentQueries = new QueryMessage[0];
  QueryTimer currentTimer = null;
  GuiAnt container;
  JLabel jLabel2 = new JLabel();
  JButton jButton3 = new JButton();

  ArrayList currentResultSet = new ArrayList();
  ArrayList currentSupernodeSet = new ArrayList();
  boolean searchByStringInProgress = false;
  boolean searchByHashInProgress = false;
  JPanel jPanel1 = new JPanel();
  XYLayout xYLayout2 = new XYLayout();
  XYLayout xYLayout3 = new XYLayout();
  JPanel jPanel2 = new JPanel();
  XYLayout xYLayout4 = new XYLayout();
  FlowLayout flowLayout1 = new FlowLayout(FlowLayout.LEFT);
  Border border1;
  JProgressBar jProgressBar1 = new JProgressBar();
  JButton jButton4 = new JButton();
  JComboBox jComboBox1 = new JComboBox();
  JCheckBox jCheckBox1 = new JCheckBox();

  public QueryAntPanel(GuiAnt container) {
    this.container=container;
    try{
      Toolkit tk = Toolkit.getDefaultToolkit();
      MediaTracker mt = new MediaTracker(this);
      buffer = tk.getImage(this.getClass().getClassLoader().getResource(pic));
      mt.waitForAll();
    }catch(Exception e){}
    try {
      jbInit();
    }
    catch(Exception ex) {
      _logger.error("",ex);
    }
  }
  void jbInit() throws Exception {
    QueryTableModel model = new QueryTableModel(this.currentResultSet);
    TableSorter sorter = new TableSorter(model);
    resultsTable = new QueryResultTable(sorter, this);
    sorter.setTableHeader(resultsTable.getTableHeader());
    resultsTable.getTableHeader().setToolTipText(ji.JI.i("These are your search results, right click for options"));
    border1 = BorderFactory.createEmptyBorder(20,20,20,20);
    this.setLayout(flowLayout1);
    jLabel1.setText(ji.JI.i("Query String or File Hash"));
    jButton1.setMaximumSize(new Dimension(180, 34));
    jButton1.setMinimumSize(new Dimension(180, 34));
    jButton1.setPreferredSize(new Dimension(180, 34));
    jButton1.setToolTipText(ji.JI.i("Perform a search using the string in the search field (you may use " +
    "the google syntax, please read ANts help for further insfos)"));
    //jButton1.setText(ji.JI.i("Search by string"));
    jButton1.setIcon(new LabelIcon(ji.JI.i("Search by string"),DoubleBuffer.getInstance().getButton(12), jButton1));
    jButton1.addActionListener(new QueryAntPanel_jButton1_actionAdapter(this));
    jButton2.setMaximumSize(new Dimension(150, 34));
    jButton2.setMinimumSize(new Dimension(150, 34));
    jButton2.setPreferredSize(new Dimension(150, 34));
    jButton2.setToolTipText(ji.JI.i("Open a new search tab"));
    jButton2.setMargin(new Insets(2, 14, 2, 14));
    //jButton2.setText(ji.JI.i("New Query"));
    jButton2.setIcon(new LabelIcon(ji.JI.i("New Query"),DoubleBuffer.getInstance().getButton(14), jButton2));
    jButton2.addActionListener(new QueryAntPanel_jButton2_actionAdapter(this));
    jLabel2.setToolTipText(ji.JI.i("Last search state"));
    jLabel2.setText(ji.JI.i("no last search..."));
    jTextField1.setOpaque(true);
    jTextField1.setToolTipText(ji.JI.i("Insert a search string, an ants2k or an ed2k link"));
    jTextField1.setText("");
    jTextField1.addKeyListener(new QueryAntPanel_jTextField1_keyAdapter(this));
    jButton3.setMaximumSize(new Dimension(180, 34));
    jButton3.setMinimumSize(new Dimension(180, 34));
    jButton3.setPreferredSize(new Dimension(180, 34));
    jButton3.setToolTipText(ji.JI.i("Perform a search for the given ants2k:// or ed2k:// link inserted " +
    "in the search field"));
    //jButton3.setText(ji.JI.i("Search by link"));
    jButton3.setIcon(new LabelIcon(ji.JI.i("Search by link"),DoubleBuffer.getInstance().getButton(16), jButton3));
    jButton3.addActionListener(new QueryAntPanel_jButton3_actionAdapter(this));
    jPanel1.setLayout(xYLayout3);
    jPanel2.setLayout(xYLayout4);
    jScrollPane1.setMaximumSize(new Dimension(32767, 32767));
    jScrollPane1.setMinimumSize(new Dimension(400, 200));
    jScrollPane1.setPreferredSize(new Dimension(400, 200));
    this.addComponentListener(new QueryAntPanel_this_componentAdapter(this));
    jPanel2.setMinimumSize(new Dimension(600, 100));
    jPanel2.setOpaque(false);
    jPanel2.setPreferredSize(new Dimension(600, 100));
    jPanel2.setRequestFocusEnabled(true);
    jPanel1.setMinimumSize(new Dimension(470, 60));
    jPanel1.setOpaque(false);
    jPanel1.setPreferredSize(new Dimension(470, 60));
    this.setAlignmentX((float) 0.5);
    this.setBorder(border1);
    jProgressBar1.setOrientation(JProgressBar.HORIZONTAL);
    jProgressBar1.setMinimumSize(new Dimension(100, 18));
    jProgressBar1.setPreferredSize(new Dimension(100, 18));
    jProgressBar1.setToolTipText(ji.JI.i("Search progress, you may receive further results also when this reach " +
    "its end, this is only an approximative indication!"));
    jProgressBar1.setMinimum(0);
    jProgressBar1.setMaximum((int)Ant.messageTimeout/1000);
    jButton4.setMaximumSize(new Dimension(150, 34));
    jButton4.setMinimumSize(new Dimension(150, 34));
    jButton4.setPreferredSize(new Dimension(150, 34));
    jButton4.setToolTipText(ji.JI.i("Close this tab"));
    jButton4.setMargin(new Insets(2, 14, 2, 14));
    //jButton4.setText(ji.JI.i("Close"));
    jButton4.setIcon(new LabelIcon(ji.JI.i("Close"),DoubleBuffer.getInstance().getButton(13), jButton4));
    jButton4.addActionListener(new QueryAntPanel_jButton4_actionAdapter(this));
    jComboBox1.addItem("");
    jComboBox1.addItem(ji.JI.i("Pictures"));
    jComboBox1.addItem(ji.JI.i("Music"));
    jComboBox1.addItem(ji.JI.i("Video"));
    jComboBox1.addItem(ji.JI.i("ISO images"));
    jComboBox1.setSelectedItem("");
    jComboBox1.setMinimumSize(new Dimension(24, 19));
    jComboBox1.setPreferredSize(new Dimension(100, 19));
    jComboBox1.setToolTipText(ji.JI.i("Select the file types to be searched"));
    jCheckBox1.setText(ji.JI.i("Content"));
    jCheckBox1.setToolTipText(ji.JI.i("Search also in the content of the indexed files"));
    jCheckBox1.setSelected(false);
    jPanel1.add(jLabel2,      new XYConstraints(0, 5, -1, -1));
    jPanel1.add(jProgressBar1,       new XYConstraints(350, 27, -1, -1));
    jScrollPane1.getViewport().add(resultsTable, null);
    jPanel2.add(jTextField1,             new XYConstraints(0, 65, 220, -1));
    jPanel2.add(jLabel1,        new XYConstraints(0, 43, -1, -1));
    jPanel2.add(jButton1,     new XYConstraints(350, 0, -1, -1));
    jPanel2.add(jButton4,          new XYConstraints(0, 0, -1, -1));
    jPanel2.add(jButton2,           new XYConstraints(176, 0, -1, -1));
    jPanel2.add(jComboBox1,     new XYConstraints(225, 38, -1, -1));
    jPanel2.add(jButton3,   new XYConstraints(350, 50, -1, -1));
    jPanel2.add(jCheckBox1,    new XYConstraints(225, 65, 100, -1));
    this.add(jPanel2, null);
    this.add(jScrollPane1, null);
    this.add(jPanel1, null);

    TableColumn column = null;
    for (int i = 0; i < this.resultsTable.getModel().getColumnCount(); i++) {
      column = this.resultsTable.getColumnModel().getColumn(i);
      column.setPreferredWidth(QueryResultTable.columnSizes[i]);
    }
    this.resultsTable.getColumnModel().addColumnModelListener(new ColumnResizeListener(this.resultsTable));
  }

  void searchByString(boolean discardCurrentResultset){
    try{
      this.jButton1.setEnabled(false);
      this.jButton3.setEnabled(false);
      Thread.currentThread().setPriority(10);
      synchronized(this.currentResultSet){
        if(discardCurrentResultset){
          this.currentResultSet = new ArrayList();
          this.currentSupernodeSet = new ArrayList(BackgroundEngine.getInstance().getSupernodeList().keySet());
          Collections.shuffle(this.currentSupernodeSet);
        }
      }
      String query = this.jTextField1.getText();
      if(this.jComboBox1.getSelectedItem().equals(ji.JI.i("Video")))
         query += " +.avi* +.mpeg*";
      if(this.jComboBox1.getSelectedItem().equals(ji.JI.i("Pictures")))
         query += " +.jpg* +.bmp* +.tif* +.gif*";
      if(this.jComboBox1.getSelectedItem().equals(ji.JI.i("Music")))
         query += " +.rm* +.mp3* +.wav*";
      if(this.jComboBox1.getSelectedItem().equals(ji.JI.i("ISO images")))
         query += " +.iso* +.nrg* +.ccd*";
      if(query == null || query.equals("")) return;
      QueryNode qn = this.parseQueryString(this.jTextField1.getText());
      AsymmetricProvider ap = new AsymmetricProvider(false);
      //local
      QueryManager queryManager = new QueryManager(qn, this.container.cap.warriorAnt);
      ArrayList resultSet = queryManager.resultSet;
      if (discardCurrentResultset && resultSet.size() > 0) {
        this.currentQueries = new QueryMessage[1];
        this.currentQueries[0] = new QueryMessage(qn, ap.getPublicHeader());
        _logger.info("Displaying local results...");
        PropertyChangeEvent pce = new PropertyChangeEvent(this, "localQueryCompleted", this.currentQueries[0],
              queryManager.resultSet);
        this.processCurrentQuery(pce);
        _logger.info("Ricevuta parte di query file");
      }
      //remote
      boolean nullQuery = false;
      for(int q = 0; q < 3; q++){
        if(q == 0){
          this.currentSupernodeSet.retainAll(new ArrayList(BackgroundEngine.getInstance().getSupernodeList().keySet()));
          if(this.currentSupernodeSet.size() > 0){
            java.util.List supernodesSubset = new ArrayList(this.currentSupernodeSet.subList(0, (int)Math.min(5, this.currentSupernodeSet.size())));
            this.currentSupernodeSet.removeAll(supernodesSubset);
            if(this.currentSupernodeSet.size() > 0){
              this.searchByStringInProgress = true;
              jButton1.setIcon(new LabelIcon(ji.JI.i("More by string..."),DoubleBuffer.getInstance().getButton(12), jButton1));
            }else{
              this.searchByStringInProgress = false;
              jButton1.setIcon(new LabelIcon(ji.JI.i("Search by string"),DoubleBuffer.getInstance().getButton(12), jButton1));
            }
            MessageWrapper[] queryWrappers = this.container.cap.warriorAnt.doSupernodeQuery(qn, ap.getPublicHeader(), supernodesSubset);
            int startingIndex = 0;
            if(!discardCurrentResultset){
              startingIndex = this.currentQueries.length;
              QueryMessage[] tempArray = new QueryMessage[this.currentQueries.length + queryWrappers.length];
              System.arraycopy(this.currentQueries, 0, tempArray, 0, this.currentQueries.length);
              this.currentQueries = tempArray;
            }else{
              this.currentQueries = new QueryMessage[queryWrappers.length + 2];
            }
            for(int x = 0; x < queryWrappers.length; x++){
              if(queryWrappers[x].getMessage() != null && queryWrappers[x].getMessage() instanceof QueryMessage){
                this.currentQueries[x + startingIndex] = (QueryMessage) queryWrappers[x].getMessage();
              }else
                nullQuery = true;
            }
          }else{
            if(discardCurrentResultset){
              this.currentQueries = new QueryMessage[2];
            }
          }
        }else if(discardCurrentResultset){
          MessageWrapper queryWrapper = this.container.cap.warriorAnt.doQuery(qn, ap.getPublicHeader());
          if(queryWrapper.getMessage() != null && queryWrapper.getMessage() instanceof QueryMessage){
            this.currentQueries[this.currentQueries.length - q] = (QueryMessage) queryWrapper.getMessage();
          }else
            nullQuery = true;
        }
        Thread.currentThread().sleep(1000);
      }
      if (this.currentSupernodeSet.size() > 0) {
        this.jButton1.setEnabled(true);
      }
      if (this.currentTimer != null && this.currentTimer.isAlive()) {
        this.currentTimer.stop();
      }
      this.currentTimer = new QueryTimer(this);
      this.jLabel2.setText(ji.JI.i("Last search (by string)") + ": " +
                           this.jTextField1.getText());
      Component[] tabs = this.container.jTabbedPane1.getComponents();
      for (int x = 0; x < tabs.length; x++) {
        if (tabs[x] == this) {
          int max = this.jTextField1.getText().length();
          if (max > 10)
            max = 10;
          this.container.jTabbedPane1.setIconAt(x,
              new LabelIcon(ji.JI.i("Search")+" ["+this.currentResultSet.size()+"]: " + this.jTextField1.getText().substring(0, max),DoubleBuffer.getInstance().getButton(12), this));
          return;
        }
      }
      if(nullQuery){
        this.jLabel2.setText(ji.JI.i("Last search (by string) failed! TRY TO DECREASE YOUR NEIGHBOURS, PROBABLY YOU HAVE TOO MANY CONNECTIONS."));
        throw new Exception("Null query Message in MessageWrapper");
      }
    }catch(Exception ex){
      _logger.error("Errore nella richiesta di esecuzione query",ex);
      this.jButton1.setEnabled(true);
    }
  }

  void jButton1_actionPerformed(ActionEvent e) {
    if(this.searchByStringInProgress)
      this.searchByString(false);
    else
      this.searchByString(true);
  }

  public QueryNode parseQueryString(String query){
    QueryNode queryStructure = new QueryStringItem(null, query, jCheckBox1.isSelected());
    return queryStructure;
  }

  private void processCurrentQuery(PropertyChangeEvent e){
    if (e.getPropertyName().equals("queryCompleted") ||
        e.getPropertyName().equals("localQueryCompleted")) {
      synchronized(currentQueries){
        for (int q = 0; q < this.currentQueries.length; q++) {
          if (this.currentQueries[q] != null) {
            QueryMessage eventQuerySource = (QueryMessage) e.getOldValue();
            if (eventQuerySource.getLocalQueryId() ==
                currentQueries[q].getLocalQueryId()) {
              synchronized (this.currentResultSet) {
                this.currentResultSet = this.mergeQueryResults( (ArrayList) e.
                    getNewValue());
                ( (QueryTableModel) ( ( (TableSorter)this.resultsTable.getModel()).
                                     getTableModel())).setResultSet(this.
                    currentResultSet);
                this.resultsTable.revalidate();
              }

              Component[] tabs = this.container.jTabbedPane1.getComponents();
              for (int x = 0; x < tabs.length; x++) {
                if (tabs[x] == this) {
                  int max = this.jTextField1.getText().length();
                  if (max > 10)
                    max = 10;
                  this.container.jTabbedPane1.setIconAt(x,new LabelIcon(
                      ji.JI.i("Search") + " [" + this.currentResultSet.size() +
                      "]: " +
                      this.jTextField1.getText().substring(0, max),DoubleBuffer.getInstance().getButton(12), this.container.jTabbedPane1.getComponentAt(x)));
                  return;
                }
              }
            }
          }
        }
      }
    }
  }

  public void propertyChange(PropertyChangeEvent e) {
    final PropertyChangeEvent event = e;
    Thread processor = new Thread(){
      public void run(){
        processCurrentQuery(event);
      }
    };
    processor.setPriority(1);
    processor.start();
  }

  public ArrayList mergeQueryResults(ArrayList resultSet){
    ArrayList tupleGroups = this.currentResultSet;
    for(int x=0; x < resultSet.size(); x++){
      if(resultSet.get(x) instanceof QueryCompletedFileTuple){
        if(tupleGroups.contains((QueryCompletedFileTuple)resultSet.get(x))){
          FileTupleGroup ftg = (FileTupleGroup)tupleGroups.get(tupleGroups.indexOf((QueryCompletedFileTuple)resultSet.get(x)));
          if(ftg.tuples.contains(resultSet.get(x)) && ftg.tuples.get(ftg.tuples.indexOf(resultSet.get(x))) instanceof QueryRemoteFileTuple)
            ftg.tuples.set(ftg.tuples.indexOf(resultSet.get(x)), resultSet.get(x));
          else if(!ftg.tuples.contains(resultSet.get(x)))
            ftg.tuples.add(resultSet.get(x));
        }else{
          QueryCompletedFileTuple qft = (QueryCompletedFileTuple)resultSet.get(x);
          FileTupleGroup ftg = new FileTupleGroup(qft.getFileHash(),qft.getSize());
          ftg.tuples.add(qft);
          tupleGroups.add(ftg);
        }
      }else if(resultSet.get(x) instanceof QueryPartialFileTuple){
        if(tupleGroups.contains((QueryPartialFileTuple)resultSet.get(x))){
          FileTupleGroup ftg = (FileTupleGroup)tupleGroups.get(tupleGroups.indexOf((QueryPartialFileTuple)resultSet.get(x)));
          if(ftg.tuples.contains(resultSet.get(x)) && ftg.tuples.get(ftg.tuples.indexOf(resultSet.get(x))) instanceof QueryRemoteFileTuple)
            ftg.tuples.set(ftg.tuples.indexOf(resultSet.get(x)), resultSet.get(x));
          else if(!ftg.tuples.contains(resultSet.get(x)))
            ftg.tuples.add(resultSet.get(x));
        }else{
          QueryPartialFileTuple qpft = (QueryPartialFileTuple)resultSet.get(x);
          FileTupleGroup ftg = new FileTupleGroup(qpft.getFileHash(),qpft.getSize());
          ftg.tuples.add(qpft);
          tupleGroups.add(ftg);
        }
      }else if(resultSet.get(x) instanceof QueryRemoteFileTuple){
        if(!tupleGroups.contains((QueryRemoteFileTuple)resultSet.get(x)) &&
           !this.container.cap.warriorAnt.getIdent().equals(((QueryRemoteFileTuple)resultSet.get(x)).getOwnerID())){
          QueryRemoteFileTuple qrft = (QueryRemoteFileTuple)resultSet.get(x);
          FileTupleGroup ftg = new FileTupleGroup(qrft.getFileHash(),qrft.getSize());
          ftg.tuples.add(qrft);
          tupleGroups.add(ftg);
        }else if(!this.container.cap.warriorAnt.getIdent().equals(((QueryRemoteFileTuple)resultSet.get(x)).getOwnerID())){
          QueryRemoteFileTuple qrft = (QueryRemoteFileTuple)resultSet.get(x);
          FileTupleGroup ftg = (FileTupleGroup)tupleGroups.get(tupleGroups.indexOf(qrft));
          if(ftg.tuples.contains(resultSet.get(x)) && ftg.tuples.get(ftg.tuples.indexOf(resultSet.get(x))) instanceof QueryRemoteFileTuple){
            QueryRemoteFileTuple oldQrft = (QueryRemoteFileTuple)ftg.tuples.get(ftg.tuples.indexOf(resultSet.get(x)));
            if(oldQrft.getLastTimeSeen().longValue() < qrft.getLastTimeSeen().longValue()){
              ftg.tuples.set(ftg.tuples.indexOf(resultSet.get(x)),qrft);
            }
          }
          else if(!ftg.tuples.contains(resultSet.get(x))){
            ftg.tuples.add(qrft);
          }
        }
      }
    }
    return tupleGroups;
  }

  void jButton2_actionPerformed(ActionEvent e) {
    QueryAntPanel qap = new QueryAntPanel(this.container);
    this.container.queryPanels.add(qap);
    this.container.jTabbedPane1.add(qap, new LabelIcon(ji.JI.i("Search"), DoubleBuffer.getInstance().getButton(12), qap));
    this.container.cap.warriorAnt.getPropertyChangeSupport().
        addPropertyChangeListener(qap);
  }

  public void resetQueryTimer(){
    if (this.currentTimer != null && this.currentTimer.isAlive()) {
      this.currentTimer.stop();
    }
    this.currentTimer = new QueryTimer(this);
  }

  void searchByHash(boolean discardCurrentResultset){
    try {
      this.jButton3.setEnabled(false);
      this.jButton1.setEnabled(false);
      Thread.currentThread().setPriority(10);
      synchronized(this.currentResultSet){
        if(discardCurrentResultset){
          this.currentResultSet = new ArrayList();
          this.currentSupernodeSet = new ArrayList(BackgroundEngine.getInstance().
              getSupernodeList().keySet());
          Collections.shuffle(this.currentSupernodeSet);
        }
      }
      String query = null;
      boolean antsHash;
      if(this.jTextField1.getText().toLowerCase().split("\\x7c")[0].equals("ed2k://")){
        try{
          antsHash = false;
          query = this.jTextField1.getText().toLowerCase().split("\\x7c")[4];
        }catch(Exception e){
          JOptionPane.showMessageDialog(this, ji.JI.i("Not a valid ED2K link"),ji.JI.i("Error in performing search"),JOptionPane.ERROR_MESSAGE);
          return;
        }
      }else if(this.jTextField1.getText().toLowerCase().split("\\x7c")[0].equals("ants2k://")){
        try{
          antsHash = true;
          query = this.jTextField1.getText().toLowerCase().split("\\x7c")[4];
        }catch(Exception e){
          JOptionPane.showMessageDialog(this, ji.JI.i("Not a valid ANTS2K link"),ji.JI.i("Error in performing search"),JOptionPane.ERROR_MESSAGE);
          return;
        }
      }else{
        JOptionPane.showMessageDialog(this, ji.JI.i("Not a valid ANTS2K or ED2K link"),ji.JI.i("Error in performing search"),JOptionPane.ERROR_MESSAGE);
        return;
      }
      if(query == null || query.equals("")) return;
      QueryNode qsi = new QueryHashItem(null, query, antsHash ? QueryHashItem.ANTS_HASH : QueryHashItem.ED2K_HASH, false);
      AsymmetricProvider ap = new AsymmetricProvider(false);
      //local
      QueryManager queryManager = new QueryManager(qsi, this.container.cap.warriorAnt);
      ArrayList resultSet = queryManager.resultSet;
      if (discardCurrentResultset && resultSet.size() > 0) {
        this.currentQueries = new QueryMessage[1];
        this.currentQueries[0] = new QueryMessage(qsi, ap.getPublicHeader());
        _logger.info("Displaying local results...");
        PropertyChangeEvent pce = new PropertyChangeEvent(this, "localQueryCompleted", this.currentQueries[0],
              queryManager.resultSet);
        this.processCurrentQuery(pce);
        _logger.info("Ricevuta parte di query file");
      }
      //remote
      boolean nullQuery = false;
      boolean doneSupernodeQuery = false;
      for(int q = 0; q < 3 && !nullQuery && !doneSupernodeQuery; q++){
        if(q == 0){
          this.currentSupernodeSet.retainAll(new ArrayList(BackgroundEngine.getInstance().getSupernodeList().keySet()));
          if(this.currentSupernodeSet.size() > 0){
            java.util.List supernodesSubset = new ArrayList(this.currentSupernodeSet.subList(0, (int)Math.min(5, this.currentSupernodeSet.size())));
            this.currentSupernodeSet.removeAll(supernodesSubset);
            if(this.currentSupernodeSet.size() > 0){
              this.searchByHashInProgress = true;
              jButton3.setIcon(new LabelIcon(ji.JI.i("More by hash..."),DoubleBuffer.getInstance().getButton(12), jButton1));
            }else{
              this.searchByHashInProgress = false;
              jButton3.setIcon(new LabelIcon(ji.JI.i("Search by hash"),DoubleBuffer.getInstance().getButton(12), jButton1));
            }
            MessageWrapper[] queryWrappers = this.container.cap.warriorAnt.doSupernodeQuery(qsi, ap.getPublicHeader(), supernodesSubset);
            int startingIndex = 0;
            if(!discardCurrentResultset){
              startingIndex = this.currentQueries.length;
              QueryMessage[] tempArray = new QueryMessage[this.currentQueries.length + queryWrappers.length];
              System.arraycopy(this.currentQueries, 0, tempArray, 0, this.currentQueries.length);
              this.currentQueries = tempArray;
            }else{
              this.currentQueries = new QueryMessage[queryWrappers.length + 2];
            }
            for(int x = 0; x < queryWrappers.length && !nullQuery; x++){
              if(queryWrappers[x].getMessage() != null && queryWrappers[x].getMessage() instanceof QueryMessage){
                this.currentQueries[x + startingIndex] = (QueryMessage) queryWrappers[x].getMessage();
              }else
                nullQuery = true;
            }
          }else{
            if(discardCurrentResultset){
              this.currentQueries = new QueryMessage[2];
            }
          }
        }else if(discardCurrentResultset){
          MessageWrapper queryWrapper = this.container.cap.warriorAnt.doQuery(qsi, ap.getPublicHeader());
          if(queryWrapper.getMessage() != null && queryWrapper.getMessage() instanceof QueryMessage){
            this.currentQueries[this.currentQueries.length - q] = (QueryMessage) queryWrapper.getMessage();
          }else
            nullQuery = true;
        }
        Thread.currentThread().sleep(1000);
      }
      if(!nullQuery){
        if (this.currentSupernodeSet.size() > 0) {
          this.jButton3.setEnabled(true);
        }
        if (this.currentTimer != null && this.currentTimer.isAlive()) {
          this.currentTimer.stop();
        }
        this.currentTimer = new QueryTimer(this);
        this.jLabel2.setText(ji.JI.i("Last search (by hash)") + ": " +
                             this.jTextField1.getText());
        Component[] tabs = this.container.jTabbedPane1.getComponents();
        for (int x = 0; x < tabs.length; x++) {
          if (tabs[x] == this) {
            int max = this.jTextField1.getText().length();
            if (max > 10)
              max = 10;
            this.container.jTabbedPane1.setIconAt(x,new LabelIcon(
                ji.JI.i("Search")+" ["+this.currentResultSet.size()+"]: " +
                this.jTextField1.getText().
                substring(0, max), DoubleBuffer.getInstance().getButton(12), this.container.jTabbedPane1.getComponentAt(x)));
            return;
          }
        }
      }
      else{
        this.jLabel2.setText(ji.JI.i("Last search (by hash) failed! TRY TO DECREASE YOUR NEIGHBOURS, PROBABLY YOU HAVE TOO MANY CONNECTIONS."));
        throw new Exception("Null query Message in MessageWrapper");
      }
    }
    catch (Exception ex) {
      _logger.error("Errore nella richiesta di esecuzione query",ex);
      this.jButton3.setEnabled(true);
    }
  }

  void jButton3_actionPerformed(ActionEvent e) {
    if(this.searchByHashInProgress)
      this.searchByHash(false);
    else
      this.searchByHash(true);
  }

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (buffer != null) {
      int posX = (this.getWidth() - 650) / 2;
      int posY = (this.getHeight() - 550) / 2;
      if(posX < 0) posX = 0;
      if(posY < 0) posY = 0;
      g.drawImage(buffer, posX, posY, this);
    }
  }

  void this_componentResized(ComponentEvent e) {
    this.jPanel1.setPreferredSize(new Dimension(this.getWidth(),this.jPanel1.getHeight()));
    this.jPanel1.setSize(new Dimension(this.getWidth(),this.jPanel1.getHeight()));
    this.jPanel2.setPreferredSize(new Dimension(this.getWidth(),this.jPanel2.getHeight()));
    this.jPanel2.setSize(new Dimension(this.getWidth(),this.jPanel2.getHeight()));
    this.jScrollPane1.setPreferredSize(new Dimension(this.getWidth()-50, this.getHeight() - 200));
    this.jScrollPane1.setSize(new Dimension(this.getWidth()-50, this.getHeight() - 200));
  }




  void jTextField1_keyReleased(KeyEvent e) {
    if(e.getKeyChar() == '\n'){
      if (this.searchByStringInProgress && this.jButton1.isEnabled())
        this.searchByString(false);
      else if (this.jButton1.isEnabled())
        this.searchByString(true);
    }else{
      this.searchByHashInProgress = false;
      jButton3.setIcon(new LabelIcon(ji.JI.i("Search by hash"),DoubleBuffer.getInstance().getButton(12), jButton1));
      this.jButton1.setEnabled(true);
      this.searchByStringInProgress = false;
      jButton1.setIcon(new LabelIcon(ji.JI.i("Search by string"),DoubleBuffer.getInstance().getButton(12), jButton1));
      this.jButton3.setEnabled(true);
    }
  }

  void jButton4_actionPerformed(ActionEvent e) {
    this.container.getTabbedPane().remove(this);
  }
}

class QueryAntPanel_jButton1_actionAdapter implements java.awt.event.ActionListener {
  QueryAntPanel adaptee;

  QueryAntPanel_jButton1_actionAdapter(QueryAntPanel adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    final ActionEvent event = e;
    Thread processor = new Thread() {
      public void run() {
        adaptee.jButton1_actionPerformed(event);
      }
    };
    processor.setPriority(10);
    processor.start();
  }
}

class QueryAntPanel_jButton2_actionAdapter implements java.awt.event.ActionListener {
  QueryAntPanel adaptee;

  QueryAntPanel_jButton2_actionAdapter(QueryAntPanel adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jButton2_actionPerformed(e);
  }
}

class QueryAntPanel_jButton3_actionAdapter implements java.awt.event.ActionListener {
  QueryAntPanel adaptee;

  QueryAntPanel_jButton3_actionAdapter(QueryAntPanel adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    final ActionEvent event = e;
    Thread processor = new Thread() {
      public void run() {
        adaptee.jButton3_actionPerformed(event);
      }
    };
    processor.setPriority(10);
    processor.start();
  }
}

class QueryAntPanel_this_componentAdapter extends java.awt.event.ComponentAdapter {
  QueryAntPanel adaptee;

  QueryAntPanel_this_componentAdapter(QueryAntPanel adaptee) {
    this.adaptee = adaptee;
  }
  public void componentResized(ComponentEvent e) {
    adaptee.this_componentResized(e);
  }
}

class QueryAntPanel_jTextField1_keyAdapter extends java.awt.event.KeyAdapter {
  QueryAntPanel adaptee;

  QueryAntPanel_jTextField1_keyAdapter(QueryAntPanel adaptee) {
    this.adaptee = adaptee;
  }
  public void keyReleased(KeyEvent e) {
    final KeyEvent event = e;
    final SwingWorker worker = new SwingWorker() {
      public Object construct() {
        adaptee.jTextField1_keyReleased(event);
        return null;
      }
    };
    worker.start();
  }
}

class QueryTimer extends Thread{
  long loops = Ant.messageTimeout / 1000;
  QueryAntPanel caller;

  public QueryTimer(QueryAntPanel caller){
    this.caller = caller;
    this.setPriority(1);
    this.start();
    while(!this.isAlive())
      try {
        Thread.currentThread().sleep(1000); //.yield()
      }
      catch (InterruptedException ex) {
      }
    this.caller.jProgressBar1.setValue(0);
  }

  public void run(){
    while(loops > 0){
      try {
        this.sleep(1000);
      }
      catch (InterruptedException ex) {
      }
      loops--;
      this.caller.jProgressBar1.setValue(this.caller.jProgressBar1.getValue() + 1);
    }
    if(caller.currentSupernodeSet.size() == 0){
      this.caller.searchByHashInProgress = false;
      this.caller.jButton3.setIcon(new LabelIcon(ji.JI.i("Search by hash"),
                                                 DoubleBuffer.getInstance().
                                                 getButton(12),
                                                 this.caller.jButton1));
      this.caller.jButton1.setEnabled(true);
      this.caller.searchByStringInProgress = false;
      this.caller.jButton1.setIcon(new LabelIcon(ji.JI.i("Search by string"),
                                                 DoubleBuffer.getInstance().
                                                 getButton(12),
                                                 this.caller.jButton1));
      this.caller.jButton3.setEnabled(true);
    }
  }
}

class QueryAntPanel_jButton4_actionAdapter implements java.awt.event.ActionListener {
  QueryAntPanel adaptee;

  QueryAntPanel_jButton4_actionAdapter(QueryAntPanel adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jButton4_actionPerformed(e);
  }
}
